﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using GeoAPI.Geometries;
using NetTopologySuite.Algorithm;
using NetTopologySuite.Algorithm.Locate;
using NetTopologySuite.Geometries;
using NetTopologySuite.Utilities;

namespace NetTopologySuite.GeometriesGraph
{
	public abstract class EdgeEndStar
	{
		public abstract void Insert(EdgeEnd e);

		protected void InsertEdgeEnd(EdgeEnd e, EdgeEnd obj)
		{
			this.edgeMap[e] = obj;
			this.edgeList = null;
		}

		public Coordinate Coordinate
		{
			get
			{
				IEnumerator<EdgeEnd> enumerator = this.GetEnumerator();
				if (!enumerator.MoveNext())
				{
					return null;
				}
				return enumerator.Current.Coordinate;
			}
		}

		public int Degree
		{
			get
			{
				return this.edgeMap.Count;
			}
		}

		public IEnumerator<EdgeEnd> GetEnumerator()
		{
			return this.Edges.GetEnumerator();
		}

		public IList<EdgeEnd> Edges
		{
			get
			{
				if (this.edgeList == null)
				{
					this.edgeList = new List<EdgeEnd>(this.edgeMap.Values);
				}
				return this.edgeList;
			}
		}

		public EdgeEnd GetNextCW(EdgeEnd ee)
		{
			IList<EdgeEnd> edges = this.Edges;
			int num = this.edgeList.IndexOf(ee);
			int index = num - 1;
			if (num == 0)
			{
				index = this.edgeList.Count - 1;
			}
			return this.edgeList[index];
		}

		public virtual void ComputeLabelling(GeometryGraph[] geomGraph)
		{
			this.ComputeEdgeEndLabels(geomGraph[0].BoundaryNodeRule);
			this.PropagateSideLabels(0);
			this.PropagateSideLabels(1);
			bool[] array = new bool[2];
			foreach (EdgeEnd edgeEnd in this.Edges)
			{
				Label label = edgeEnd.Label;
				for (int i = 0; i < 2; i++)
				{
					if (label.IsLine(i) && label.GetLocation(i) == Location.Boundary)
					{
						array[i] = true;
					}
				}
			}
			foreach (EdgeEnd edgeEnd2 in this.Edges)
			{
				Label label2 = edgeEnd2.Label;
				for (int j = 0; j < 2; j++)
				{
					if (label2.IsAnyNull(j))
					{
						Location location;
						if (array[j])
						{
							location = Location.Exterior;
						}
						else
						{
							Coordinate coordinate = edgeEnd2.Coordinate;
							location = this.GetLocation(j, coordinate, geomGraph);
						}
						label2.SetAllLocationsIfNull(j, location);
					}
				}
			}
		}

		private void ComputeEdgeEndLabels(IBoundaryNodeRule boundaryNodeRule)
		{
			foreach (EdgeEnd edgeEnd in this.Edges)
			{
				edgeEnd.ComputeLabel(boundaryNodeRule);
			}
		}

		private Location GetLocation(int geomIndex, Coordinate p, GeometryGraph[] geom)
		{
			if (this._ptInAreaLocation[geomIndex] == Location.Null)
			{
				this._ptInAreaLocation[geomIndex] = SimplePointInAreaLocator.Locate(p, geom[geomIndex].Geometry);
			}
			return this._ptInAreaLocation[geomIndex];
		}

		public bool IsAreaLabelsConsistent(GeometryGraph geometryGraph)
		{
			this.ComputeEdgeEndLabels(geometryGraph.BoundaryNodeRule);
			return this.CheckAreaLabelsConsistent(0);
		}

		private bool CheckAreaLabelsConsistent(int geomIndex)
		{
			IList<EdgeEnd> edges = this.Edges;
			if (edges.Count <= 0)
			{
				return true;
			}
			int index = edges.Count - 1;
			Location location = edges[index].Label.GetLocation(geomIndex, Positions.Left);
			Assert.IsTrue(location != Location.Null, "Found unlabelled area edge");
			Location location2 = location;
			foreach (EdgeEnd edgeEnd in this.Edges)
			{
				Label label = edgeEnd.Label;
				Assert.IsTrue(label.IsArea(geomIndex), "Found non-area edge");
				Location location3 = label.GetLocation(geomIndex, Positions.Left);
				Location location4 = label.GetLocation(geomIndex, Positions.Right);
				if (location3 == location4)
				{
					return false;
				}
				if (location4 != location2)
				{
					return false;
				}
				location2 = location3;
			}
			return true;
		}

		public void PropagateSideLabels(int geomIndex)
		{
			Location location = Location.Null;
			foreach (EdgeEnd edgeEnd in this.Edges)
			{
				Label label = edgeEnd.Label;
				if (label.IsArea(geomIndex) && label.GetLocation(geomIndex, Positions.Left) != Location.Null)
				{
					location = label.GetLocation(geomIndex, Positions.Left);
				}
			}
			if (location == Location.Null)
			{
				return;
			}
			Location location2 = location;
			foreach (EdgeEnd edgeEnd2 in this.Edges)
			{
				Label label2 = edgeEnd2.Label;
				if (label2.GetLocation(geomIndex, Positions.On) == Location.Null)
				{
					label2.SetLocation(geomIndex, Positions.On, location2);
				}
				if (label2.IsArea(geomIndex))
				{
					Location location3 = label2.GetLocation(geomIndex, Positions.Left);
					Location location4 = label2.GetLocation(geomIndex, Positions.Right);
					if (location4 != Location.Null)
					{
						if (location4 != location2)
						{
							throw new TopologyException("side location conflict", edgeEnd2.Coordinate);
						}
						if (location3 == Location.Null)
						{
							Assert.ShouldNeverReachHere("found single null side (at " + edgeEnd2.Coordinate + ")");
						}
						location2 = location3;
					}
					else
					{
						Assert.IsTrue(label2.GetLocation(geomIndex, Positions.Left) == Location.Null, "found single null side");
						label2.SetLocation(geomIndex, Positions.Right, location2);
						label2.SetLocation(geomIndex, Positions.Left, location2);
					}
				}
			}
		}

		public int FindIndex(EdgeEnd eSearch)
		{
			this.GetEnumerator();
			for (int i = 0; i < this.edgeList.Count; i++)
			{
				if (this.edgeList[i] == eSearch)
				{
					return i;
				}
			}
			return -1;
		}

		public virtual void Write(StreamWriter outstream)
		{
			foreach (EdgeEnd edgeEnd in this.Edges)
			{
				edgeEnd.Write(outstream);
			}
		}

		public override string ToString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("EdgeEndStar:   " + this.Coordinate);
			foreach (EdgeEnd edgeEnd in this)
			{
				stringBuilder.AppendLine(edgeEnd.ToString());
			}
			return stringBuilder.ToString();
		}

		protected IDictionary<EdgeEnd, EdgeEnd> edgeMap = new SortedDictionary<EdgeEnd, EdgeEnd>();

		protected IList<EdgeEnd> edgeList;

		private readonly Location[] _ptInAreaLocation = new Location[]
		{
			Location.Null,
			Location.Null
		};
	}
}
